package com.zjb.demo.common.domain.server;

import com.zjb.demo.common.util.FileUtils;
import com.zjb.demo.common.util.IPUtils;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Properties;

/**
 * 服务器相关信息
 *
 * @author 庄佳彬
 * @since 2023/12/24 21:19
 */
public class Server {
    private static final int OSHI_WAIT_SECOND = 1000;
    /**
     * CPU相关信息
     */
    private CPU cpu;

    /**
     * 內存相关信息
     */
    private Mem mem;

    /**
     * JVM相关信息
     */
    private Jvm jvm;

    /**
     * 服务器相关信息
     */
    private Sys sys;

    /**
     * 磁盘相关信息
     */
    private List<SysFile> sysFiles;

    public CPU getCpu() {
        return cpu;
    }

    public Mem getMem() {
        return mem;
    }


    public Jvm getJvm() {
        return jvm;
    }


    public Sys getSys() {
        return sys;
    }


    public List<SysFile> getSysFiles() {
        return sysFiles;
    }


    public Server() {
        var si = new SystemInfo();
        var hal = si.getHardware();
        var properties = System.getProperties();

        setCpuInfo(hal.getProcessor());
        setMemInfo(hal.getMemory());
        setSysInfo(properties);
        setJvmInfo(properties);
        setSysFiles(si.getOperatingSystem());
    }

    private void setSysFiles(OperatingSystem operatingSystem) {
        var fileSystem = operatingSystem.getFileSystem();
        var fsArray = fileSystem.getFileStores();
        sysFiles = fsArray.parallelStream()
                .map(fs -> {
                    var free = fs.getUsableSpace();
                    var total = fs.getTotalSpace();
                    var used = total - free;
                    var usedBD = new BigDecimal(used);
                    var totalBD = new BigDecimal(total);
                    BigDecimal usage;
                    if (usedBD.compareTo(BigDecimal.ZERO) == 0) {
                        usage = BigDecimal.ZERO;
                    } else {
                        usage = usedBD.divide(totalBD, 4, RoundingMode.HALF_UP);
                    }
                    usage = usage.multiply(new BigDecimal(100));
                    return new SysFile(
                            fs.getMount(),
                            fs.getType(),
                            fs.getName(),
                            FileUtils.convertFileSize(total),
                            FileUtils.convertFileSize(free),
                            FileUtils.convertFileSize(used),
                            usage
                    );
                }).toList();
    }

    private void setJvmInfo(Properties properties) {
        this.jvm = new Jvm(
                Runtime.getRuntime().totalMemory(),
                Runtime.getRuntime().maxMemory(),
                Runtime.getRuntime().freeMemory(),
                properties.getProperty("java.version"),
                properties.getProperty("java.home")
        );
    }

    private void setSysInfo(Properties props) {
        this.sys = new Sys(
                IPUtils.getHostName(),
                IPUtils.getHostIp(),
                props.getProperty("user.dir"),
                props.getProperty("os.name"),
                props.getProperty("os.arch")
        );
    }

    private void setMemInfo(GlobalMemory memory) {
        this.mem = new Mem(memory.getTotal(),
                memory.getTotal() - memory.getAvailable(),
                memory.getAvailable());
    }

    private void setCpuInfo(CentralProcessor processor) {
        // CPU信息
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
        long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
        long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
        long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
        long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        this.cpu = new CPU(processor.getLogicalProcessorCount(),
                totalCpu,
                cSys,
                user,
                iowait,
                idle
        );
    }
}
